package 基础.设计模式.单例;

/**
 * 单例设计:保证一个类的对象在一个进程内部只有一份.
 * 实现方案:
 * 1)从类自身的层面进行设计(构造方法私有化,内部创建对象,外部访问对象)
 * 2)借助外部容器方式进行设计(例如 Spring中的Bean容器-Bean 池)
 */
//饿汉单例:类加载时创建对象
//适合场景: 小对象频繁用.
//存在问题:假如对象比较大(占用的资源比较多),但是又不会开始就使用这个对象,这样把对象先创建出来就会占用资源.
class Singleton01{
    private static Singleton01 instance=new Singleton01();
    private Singleton01(){}
    public static Singleton01 getInstance() {
        return instance;
    }
}

//懒汉单例:何时应用何时创建
//适合创建:适合大对象,单线程环境
//存在的问题:多线程环境下会出现线程不安全(可能会创建多个对象)
class Singleton02{
    private static Singleton02 instance;
    private Singleton02(){}
    public static Singleton02 getInstance() {
        if(instance==null){
            instance=new Singleton02();
        }
        return instance;
    }
}

//线程安全的懒汉单例 (双重校验版单例)
class Singleton03{
    /**
     * volatile关键字的作用
     * 1)禁止指令重排序(在多线程环境下,JVM可能会对指令进行重排序,提高执行效率)
     * 2)保证线程可见(线程修改变量后会直接同步给其它线程)
     */
    private static volatile Singleton03 instance;
    private Singleton03(){}
    public static Singleton03 getInstance() {
        if(instance==null){//A,B (最外层的if作用是用于减少阻塞)
            synchronized (Singleton03.class) {//A,B
                if(instance==null) {//最内层的if是为了保证instance只创建1次
                    instance = new Singleton03();
                    //1.分配空间
                    //2.属性默认初始化
                    //3.调用构造方法
                    //4.将对象内存地址赋值给instance
                }
            }
        }
        return instance;
    }
}

//基于枚举实现单例
enum Singleton04{
    instance
}

public class SingletonTests {
    public static void main(String[] args) {
        for(int i=0;i<5;i++){
            new Thread(){
                @Override
                public void run() {
                    System.out.println(Singleton03.getInstance());
                }
            }.start();
        }
    }
}
